package com.gitee.wsl.struct.tree.sample.link

import com.gitee.wsl.struct.tree.LeafElement
import com.gitee.wsl.struct.tree.NodeElement
import com.gitee.wsl.struct.tree.TreeElement

sealed interface LinkTreeElement<T> : TreeElement<T, LinkTreeElement<T>> {

    val childIndex: Int
    var next: LinkTreeElement<T>?
    var previous: LinkTreeElement<T>?

//    override fun path(): List<LinkTreeElement<T>> =
//       buildList {
//               var next: LinkTreeElement<T>? = this@LinkTreeElement
//               while (next != null) {
//                   add(next)
//                   next = next.parent
//               }
//           }
//           .reversed()

    fun previousElementsIterable(): Iterable<LinkTreeElement<T>> = Iterable {
        elementIterator(previous) { it.previous }
   }

    fun nextElementsIterable(): Iterable<LinkTreeElement<T>> = Iterable { elementIterator(next) { it.next } }

    class Leaf<T>(
        override val data: T,
        override val depth: Int,
        override val childIndex: Int,
        override val parent: LinkTreeElement<T>?,
        override var previous: LinkTreeElement<T>?,
        override var next: LinkTreeElement<T>?,
        override val elementId: Any,
   ) : LinkTreeElement<T>, LeafElement<T, LinkTreeElement<T>>

    class Node<T>(
        override val data: T,
        override val depth: Int,
        override val childIndex: Int,
        override val parent: LinkTreeElement<T>?,
        private val childrenGenerator: (parent: Node<T>) -> List<LinkTreeElement<T>>,
        override var next: LinkTreeElement<T>?,
        override var previous: LinkTreeElement<T>?,
        override val elementId: Any,
   ) : LinkTreeElement<T>, NodeElement<T, LinkTreeElement<T>> {

       override var children: List<LinkTreeElement<T>>? = null
           private set

       private fun evaluateChildren() {
           children = childrenGenerator(this)
       }

       private fun connectChildren() {
           val children = children ?: return
           if (children.isNotEmpty()) {
               next?.also {
                   it.previous = children.last()
                   children.last().next = it
               }
               next = children.first()
               children.first().previous = this
           }
       }

       private fun detachChildren() {
           val children = children ?: return
           if (children.isNotEmpty()) {
               next = children.last().next
               next?.previous = this
           }
       }

        fun open(reloadChildren: Boolean = false) {
           if (reloadChildren || children == null) evaluateChildren()
           connectChildren()
       }

        fun close() {
           detachChildren()
           children?.asSequence()?.filterIsInstance<Node<*>>()?.forEach { it.closeRecursively() }
       }

       private fun closeRecursively() {
           children?.forEach { if (it is Node) it.closeRecursively() }
       }
   }
}

private fun <T> elementIterator(initial: LinkTreeElement<T>?, next: (LinkTreeElement<T>) -> LinkTreeElement<T>?) = iterator {
    var current = initial ?: return@iterator
    yield(current)
    while (true) {
        current = next(current) ?: break
        yield(current)
    }
}